package com.siyoumi.app.sys.service;

import com.siyoumi.app.feign.view_admin.SiyoumiFeign;
import com.siyoumi.app.sys.vo.AdminLoginQrVo;
import com.siyoumi.app.sys.vo.AdminLoginVo;
import com.siyoumi.app.sys.vo.ApprVo;
import com.siyoumi.component.XBean;
import com.siyoumi.component.XJwt;
import com.siyoumi.component.XRedis;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.auth_img.AuthImgService;
import com.siyoumi.component.auth_img.impl.CodeAuthImgServiceImpl;
import com.siyoumi.component.auth_img.impl.DragAuthImgServiceImpl;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.config.SysConfig;
import com.siyoumi.entity.SysAccount;
import com.siyoumi.entity.SysAppRouter;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.service.SysAccountService;
import com.siyoumi.service.SysAppRouterService;
import com.siyoumi.service.SysAppService;
import com.siyoumi.util.*;
import com.siyoumi.component.XApp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AdminService {
    static public AdminService getBean() {
        return XSpringContext.getBean(AdminService.class);
    }

    /**
     * 登陆错误redis key
     *
     * @param accUid 帐号ID
     * @return key
     */
    protected String getRedisKeyErrCount(String accUid) {
        return RedisKey.getLoginErrCount(accUid);
    }

    /**
     * 验证码redis key
     *
     * @param ip ip地址
     * @return key
     */
    protected String getRedisKeyAuthCode(String ip) {
        return RedisKey.getLoginAuthCode(ip);
    }

    static public String getRedisKeyToken(String token) {
        return RedisKey.getAdminToken(token);
    }


    /**
     * 登陆
     *
     * @param loginVo
     */
    public XReturn login(AdminLoginVo loginVo) {
        XRedis redis = XRedis.getBean();
        //检查验证码
        String vcodeRedisKey = getRedisKeyAuthCode(XHttpContext.getIpAddr());
        AuthImgService authImg = DragAuthImgServiceImpl.getIns(vcodeRedisKey, null, null);
        XReturn rAuth = authImg.auth(loginVo.getVcode());
        if (rAuth.err()) {
            return rAuth;
        }
//        String vcodeRedis = redis.get(vcodeRedisKey);
//        if (!loginVo.getVcode().equals(vcodeRedis)) {
//            if (SysConfig.getIns().isDev()) {
//                //dev pass
//            } else {
//                return XReturn.getR(10115, "验证码错误");
//            }
//        }

        SysAccount entityAcc = SysAccountService.getBean().getAccByUserName(loginVo.getUsername());
        XReturn r = SysAccountService.getBean().isValid(entityAcc);
        if (r.err()) {
            return r;
        }


        String encPwd = XApp.encPwd(entityAcc.getAcc_x_id(), loginVo.getDecPwd());
        log.debug("md5：{}", encPwd);
        log.debug("db_pwd：{}", entityAcc.getAcc_pwd());
        if (!encPwd.equals(entityAcc.getAcc_pwd())) {
            String redisKeyErrCount = this.getRedisKeyErrCount(entityAcc.getAcc_uid());
            //
            Long errCount = redis.increment(redisKeyErrCount);
            Long errCountLeft = SysConfig.getIns().getLoginErrMax() - errCount;
            String errmsg = XStr.concat("密码错误，剩余", errCountLeft + "", "机会");
            if (errCount >= SysConfig.getIns().getLoginErrMax()) {
                SysAccountService.getBean().setLockEnd(entityAcc, 24);
                errmsg = "密码错误，帐号将被锁定24小时";
            }
            redis.expire(redisKeyErrCount, 5 * 60);
            //清掉验证码的redis
            redis.del(vcodeRedisKey);

            return XReturn.getR(10120, errmsg);
        }

        String token = getToken(entityAcc);
        //清掉验证码的redis
        redis.del(vcodeRedisKey);

        r = XReturn.getR(0);
        r.setData("token", token);

        return r;
    }

    /**
     * 扫码登陆-初始化
     */
    public XReturn loginQrInit() {
        XReturn r = XReturn.getR(0);

        String token = SiyoumiFeign.getBean().getToken(XApp.getStrID());
        r.setData("token", token);

        return r;
    }

    /**
     * 扫码登陆
     *
     * @param vo
     */
    public XReturn loginQr(AdminLoginQrVo vo) {
        SiyoumiFeign feign = SiyoumiFeign.getBean();
        XReturn r = feign.getRedisVal(vo.getOauth_code());
        if (r.err()) {
            return r;
        }
        String openid = r.getData("val");
        if (XStr.isNullOrEmpty(openid)) {
            return EnumSys.ERR_VAL.getR("授权码已失效");
        }

        SysAccount entityAcc = SysAccountService.getBean().getAccByOpenid(openid);
        r = SysAccountService.getBean().isValid(entityAcc);
        if (r.err()) {
            return r;
        }

        String token = getToken(entityAcc);

        r = XReturn.getR(0);
        r.setData("token", token);

        return r;
    }


    /**
     * 退出登陆
     *
     * @param token
     */
    public XReturn logout(String token) {
        Boolean del = XRedis.getBean().del(getRedisKeyToken(token));
        
        log.info("清站点应用缓存");
        String appsKey = SysAppService.getBean().getEntityCacheKey("apps");
        XRedis.getBean().del(appsKey);

        return XReturn.getR(0);
    }


    public XReturn center() {
        return XReturn.getR(0);
    }


    /**
     * 获取验证码，图片流
     *
     * @return 图片流
     * @throws IOException
     */
    public BufferedImage authCode() throws IOException {
        CodeAuthImgServiceImpl authImg = CodeAuthImgServiceImpl.getIns(this.getRedisKeyAuthCode(XHttpContext.getIpAddr()));
        List<BufferedImage> imgArr = authImg.getImgInfo();

//        String vcode = XApp.random(1000, 9999) + "";
//
//        BufferedImage img = XAuthImg.createAuthCode(vcode);
//
//        //记录redis
//        String redisKey = this.getRedisKeyAuthCode(XHttpContext.getIpAddr());
//        XRedis.getBean().setEx(redisKey, vcode, 60);

        return imgArr.get(0);
    }

    /**
     * 图片拖拽
     *
     * @throws IOException
     */
    public XReturn authImgDrag() throws IOException {
        String resPath = SysConfig.getIns().getResPath();
        String resImgBase = XStr.concat(resPath, "auth_img/");
        List<String> imgBgArr = new ArrayList<>();
        List<String> imgHoldArr = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            imgBgArr.add(XStr.concat(resImgBase + i, ".png"));
            imgHoldArr.add(XStr.concat(resImgBase, "j" + i, ".png"));
        }

        String redisKey = this.getRedisKeyAuthCode(XHttpContext.getIpAddr());
        AuthImgService authImg = DragAuthImgServiceImpl.getIns(redisKey, imgBgArr, imgHoldArr);
        return authImg.authInit();
    }

    /**
     * 菜单转换成主菜单显示
     *
     * @param list 数据库菜单列表
     * @return 主菜单列表
     */
    public List<ApprVo> appRouterToApprVo(List<SysAppRouter> list) {
        //获取所有主菜单
        List<SysAppRouter> listPid = list.stream().filter(entity ->
        {
            if (XStr.isNullOrEmpty(entity.getAppr_pid())) {
                return true;
            }
            return false;
        }).collect(Collectors.toList());

        List<ApprVo> listData = new ArrayList<>();
        for (SysAppRouter p : listPid) {
            //根据pid获取所有子菜单
            List<SysAppRouter> listChild = list.stream().filter(item ->
            {
                return item.getAppr_pid().equals(p.getKey());
            }).collect(Collectors.toList());

            //主菜单
            ApprVo pVo = new ApprVo();
            XBean.copyProperties(p, pVo);
            pVo.setMetaTitle(SysAppRouterService.getBean().getMetaTitle(p));

            //子菜单
            List<ApprVo> listChildVo = listChild.stream().map(item ->
            {
                ApprVo pVoChildren = new ApprVo();
                XBean.copyProperties(item, pVoChildren);
                pVoChildren.setMetaTitle(SysAppRouterService.getBean().getMetaTitle(item));

                return pVoChildren;
            }).collect(Collectors.toList());

            pVo.setChildren(listChildVo);
            listData.add(pVo);
        }

        return listData;
    }


    /**
     * 获取token，封装多一层redis
     * 用于控制退款登陆
     *
     * @param entity
     * @return
     */
    private String getToken(SysAccount entity) {
        XRedis redis = XRedis.getBean();
        //单点登陆，先删除旧的token
        String tokenLiveKey = RedisKey.getAdminTokenLive(entity.getX(), entity.getAcc_uid());
        String tokenOld = redis.get(tokenLiveKey);
        if (XStr.hasAnyText(tokenOld)) {
            redis.del(getRedisKeyToken(tokenOld));
        }

        XReturn r = XReturn.getR(0);
        r.setData("acc_x_id", entity.getX());
        r.setData("acc_id", entity.getKey());
        r.setData("nonce_str", XApp.getID());

        Integer expireSecond = 3600 * 6;
        XJwt jwt = XJwt.getBean();
        String jwtToken = jwt.getToken(r, expireSecond);

        //记录redis
        String token = XStr.md5(XApp.getStrID());
        redis.setEx(getRedisKeyToken(token), jwtToken, expireSecond);
        //记录存活的token
        redis.setEx(tokenLiveKey, token, expireSecond);

        return token;
    }
}
